package com.vanrui.pcp.autocode.template;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.vanrui.pcp.autocode.constants.Constant;
import com.vanrui.pcp.autocode.jdbc.JDBCData;
import com.vanrui.pcp.autocode.model.entry.Config;
import com.vanrui.pcp.autocode.model.entry.Entry;
import com.vanrui.pcp.autocode.model.entry.Field;
import com.vanrui.pcp.autocode.model.entry.ProjectClass;
import com.vanrui.pcp.autocode.model.entry.Table;
import com.vanrui.pcp.autocode.model.entry.Template;
import com.vanrui.pcp.autocode.utils.StringUtilu;

import freemarker.template.TemplateModel;
import freemarker.template.Version;

public class DataFactory {
	
	private final static Logger logger = Logger.getLogger(DataFactory.class);
	
	private final static String templateType = ".flt";
	private final static String userName;
	static{
		Map<String, String> map = System.getenv();
	    userName = map.get("USERNAME");// 获取用户名
	}
	
	private Config config;
	private Entry entry;
	private List<ProjectClass> clazzs = new ArrayList<ProjectClass>();
	private Map<Object, Object> classData = new HashMap<Object, Object>();
	private Table table;
	
	public DataFactory(Config config, Table table) throws Exception{
		this.config = config;
		this.table = table;
		initData();
	}
	
	/**
	 * 初始化数据
	 * @throws Exception
	 */
	private void initData() throws Exception{
		getJdbcData();
		initProjectClass();
	}
	
	/**
	 * 初始化类数据
	 */
	private void initProjectClass(){
		Map<String, Template> templates = config.getTemplates();
		for (String key : templates.keySet()) {
			Template template = templates.get(key);
			ProjectClass clazz = new ProjectClass(entry);
			clazz.setTemplate(key);
			clazz.setPackage_(template.getPckgName());
			clazz.setPrefix(template.getPrefix());
			clazz.setSuffix(template.getSuffix());
			clazz.setFileType(template.getFileType());
			dealClass(clazz);
			clazzs.add(clazz);
		}
		
		for (ProjectClass clazz : clazzs) {
			Map<String, Object> _clazz = fromFieldToProperties(clazz);
			classData.put(clazz.getTemplate().replaceAll(templateType, ""), _clazz);
		}
		for (ProjectClass clazz : clazzs) {
			clazz.setClassData(classData);
		}
	}
	
	private Map<String, Object> fromFieldToProperties(ProjectClass clazz){
		//数据源  
        Map<String, Object> data = new HashMap<String, Object>(); 
        data.put(Constant.CLASS_NAME, clazz.getClassName());
        data.put(Constant.PACKAGE_, clazz.getPackage_());
        data.put(Constant.FILE_NAME, clazz.getFileName());
        data.put(Constant.TEMPLATE, clazz.getTemplate());
        data.put(Constant.FILE_DIRECTORY, clazz.getFileDirectory());
        data.put(Constant.FILE_PATH, clazz.getFilePath());
        data.put(Constant.PREFIX, clazz.getPrefix());
        data.put(Constant.SUFFIX, clazz.getSuffix());
        data.put(Constant.PROJECT_PATH, clazz.getProjectPath());
        data.put(Constant.ENTRY_NAME, clazz.getEntryName());
        data.put(Constant.TABLE_NAME, clazz.getTableName());
        data.put(Constant.TABLE_ALIAS, clazz.getTableAlias());
        data.put(Constant.COMMENT, clazz.getComment());
        data.put("author", userName);
        
        List<Map<Object, Object>> pros = new ArrayList<Map<Object, Object>>();
        for (Field field: clazz.getFields()) {
        	Map<Object, Object> pro = new HashMap<Object, Object>();
            pro.put(Constant.COLUMN_NAME, field.getColumnName()); //字段在数据表中的名字
            pro.put(Constant.FIELD_NAME, field.getFieldName());  //字段名字
            pro.put(Constant.FIELD_METHOD_NAME, field.getFieldMethodName());  //字段的getter和setter对应的名字
            pro.put(Constant.FIELD_COMMENT, field.getFieldComment());  //字段的注释
            pro.put(Constant.FIELD_TYPE, field.getFieldType());  //字段类型，简称的类型
            pro.put(Constant.COLUMN_TYPE, field.getColumnType());  //数据库里面该字段类型
            pro.put(Constant.DEFAULT_VALUE, field.getDefaultValue());  //数据库里面该字段默认值
            
            pros.add(pro);
		}
        
        data.put(Constant.PROS, pros);
		return data;
	}
	
	private void dealClass(ProjectClass clazz){
		
		StringBuffer _className = new StringBuffer();
		_className.append(clazz.getPrefix());
		_className.append(StringUtilu.getStrWithoutUnderline(clazz.getEntryName()));
		_className.append(clazz.getSuffix());
		clazz.setClassName(StringUtilu.getFirstUpperStr(_className.toString()));
		
		_className.append(Constant.SEPARATOR_POINT).append(clazz.getFileType());
		clazz.setFileName(StringUtilu.getFirstUpperStr(_className.toString()));
		
		StringBuffer fileDirectory = new StringBuffer();
		String package_ = clazz.getPackage_();
		package_ = StringUtils.isNotBlank(package_) ? "/"+package_.replace(".", "/") : "";
		fileDirectory.append(config.getProjectPath()).append("/src").append(package_);
		clazz.setFileDirectory(fileDirectory.toString());
		
		clazz.setFilePath(clazz.getFileDirectory() + "/" + clazz.getFileName());
	}
	
	/**
	 * 获取数据库的表信息
	 * @param tableName 
	 * @param comment 
	 * @throws Exception
	 */
	private void getJdbcData() throws Exception{
		JDBCData jdbcData = new JDBCData(config.getJdbcConfig(), table.getTableName());
		List<Field> fields = jdbcData.getTableFields();
		entry = new Entry();
		entry.setComment(table.getComment());
		entry.setTableName(table.getTableName());
		entry.setEntryName(StringUtilu.getStrWithoutUnderline(table.getTableAlias()));
		entry.setFields(fields);
		initFields();
	}
	
	/**
	 * 初始化表字段数据
	 */
	private void initFields(){
		List<Field> fields = entry.getFields();
		for (Field field : fields) {
			String columnName = field.getColumnName();
			field.setFieldName(StringUtilu.getStrWithoutUnderline(columnName));
			field.setFieldMethodName(StringUtilu.getFirstUpperStr(field.getFieldName()));
			field.setFieldType(getTypeFromColumnType(field.getColumnType()));
			field.setDefaultValue(getDefaultValue(field.getDefaultValue()));
		}
	}
	
	private String getDefaultValue(Object value) {
		
		return String.valueOf(value);
	}

	/**
	 * 根据配置的映射将数据库的类型转换为字段的类型
	 * @param columnType
	 * @return
	 */
	private String getTypeFromColumnType(String columnType){
		Map<String, String> types = config.getTypes();
		String type = types.get(columnType);
		if(StringUtils.isBlank(type)){
			type = types.get(Constant.ASTERISK);
		}
		return type;
	}
	
	/**
	 * 获取配置中定义的宏变量
	 * @return
	 */
	public Map<String, TemplateModel> getVariableMap(){
		return config.getVariables();
	}
	
	/**
	 * 获取配置的模板目录
	 * @return
	 */
	public String getTemplateDirectory(){
		 return config.getTemplateDir();
	 }

	public List<ProjectClass> getProjectClazzs() {
		return clazzs;
	}

	/**
	 * 获取配置的freemarker版本
	 * @return
	 */
	public Version getVersion() {
		return config.getVersion();
	}

	public Entry getEntry() {
		return entry;
	}

	public void setEntry(Entry entry) {
		this.entry = entry;
	}

	public Config getConfig() {
		return config;
	}

	public List<ProjectClass> getClazzs() {
		return clazzs;
	}

	public Map<Object, Object> getClassData() {
		return classData;
	}

	public Table getTable() {
		return table;
	}

	public void setTable(Table table) {
		this.table = table;
	}
}
